package com.cxyjy.travelguide.service.Impl;

import com.alibaba.fastjson.JSON;
import com.cxyjy.common.BusinessException;
import com.cxyjy.common.util.JFileUtil;
import com.cxyjy.common.util.JObjectUtil;
import com.cxyjy.common.util.JResponse;
import com.cxyjy.common.util.ResultUtil;
import com.cxyjy.travelguide.service.ImageMatchService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.cxyjy.common.constants.ImageMatchConstants.IMAGE_MATCH_URL;
import static com.cxyjy.common.util.ResultCode.NO_IMAGE_FOUNDED;
import static com.cxyjy.common.util.ResultCode.NO_IMAGE_MATCH;

/**
 * @Author: jony
 * @Date : 2025/4/18 08:41
 * @VERSION v1.0
 */
@Service
public class ImageMatchMatchServiceImpl implements ImageMatchService {
    @Override
    public JResponse matchImage(MultipartFile multipartFile, String tags, int limit) throws Exception {
        // 验证文件扩展名
        String fileName = multipartFile.getOriginalFilename();
        if (fileName == null || !fileName.contains(".")) {
            return ResultUtil.error(NO_IMAGE_FOUNDED);
        }
        // 将图片文件转换成Base64编码
        String imageBase64 = JFileUtil.convertToBase64(multipartFile);

        // URL编码Base64数据
        String encodedImage = URLEncoder.encode(imageBase64, StandardCharsets.UTF_8.toString());
        String requestBody = "rn=100&image=" + encodedImage;
        if(JObjectUtil.isNotEmpty(tags)){
            requestBody += "&tags=" + tags;
        }
        return computeResultList(requestBody, limit);
    }

    @Override
    public JResponse matchImage(String imageUrl, String tags, int limit) throws Exception {
        if (!JFileUtil.isImageUrl(imageUrl)) {
            return ResultUtil.error(NO_IMAGE_FOUNDED);
        }
        String requestBody = "rn=100&url=" + URLEncoder.encode(imageUrl, "UTF-8");
        if(JObjectUtil.isNotEmpty(tags)){
            requestBody += "&tags=" + tags;
        }
        return computeResultList(requestBody, limit);
    }

    public JResponse computeResultList(String requestBody, int limit) throws Exception {
        HttpURLConnection conn = (HttpURLConnection) IMAGE_MATCH_URL.openConnection();
        try {
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Accept", "application/json");

            // 发送请求
            try (OutputStream os = conn.getOutputStream()) {
                os.write(requestBody.getBytes(StandardCharsets.UTF_8));
            }

            // 处理响应
            int responseCode = conn.getResponseCode();
            String responseStr;
            try (InputStream is = responseCode == HttpURLConnection.HTTP_OK
                    ? conn.getInputStream()
                    : conn.getErrorStream()) {
                responseStr = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))
                        .lines().collect(Collectors.joining());
            }

            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new IOException("API请求失败: " + responseCode + " - " + responseStr);
            }

            Map<String, Object> responseMap = JObjectUtil.toMap(JSON.parse(responseStr));
            if(JObjectUtil.toInteger(responseMap.get("result_num"))==0){
                return ResultUtil.error(NO_IMAGE_MATCH);
            }
            List<Map<String, Object>> responseList = (List<Map<String, Object>>) responseMap.get("result");
            Map<String, Map<String, Object>> resultMap = new HashMap<>();
            // 定义最大分值（100%）和最小分值（0%）
            BigDecimal MAX_SCORE = BigDecimal.ONE; // 1.0
            BigDecimal MIN_SCORE = BigDecimal.ZERO; // 0.0
            //取每个文物相似度最高分输出，非平均分
            for (Map<String, Object> item : responseList) {
                String brief = JObjectUtil.stringValue(item.get("brief"));
                Object scoreObj = item.get("score");
                BigDecimal currentScore = null;
                if (scoreObj instanceof Number) {
                    // 1. 安全转换为BigDecimal
                    Number scoreNum = (Number) scoreObj;
                    currentScore = BigDecimal.valueOf(scoreNum.doubleValue());

                    // 2. 限制最大值不超过1.0（100%）
                    if (currentScore.compareTo(MAX_SCORE) > 0) {
                        currentScore = MAX_SCORE;
                    }
                    // 3. 限制最小值不低于0.0（可选，根据业务是否允许负分）
                    if (currentScore.compareTo(MIN_SCORE) < 0) {
                        throw new BusinessException("分值为负，不合法，请检查图库！");
                    }
                } else {
                    // 4. 异常情况处理（如 score 是 String 或 null，根据业务补充）
                    throw new BusinessException("score 字段类型不合法，必须是数字类型（Integer/Float/Double）");
                }
                item.put("score", currentScore);
                if (resultMap.containsKey(brief)) {
                    BigDecimal existingScore = (BigDecimal) resultMap.get(brief).get("score");
                    if (currentScore.compareTo(existingScore) > 0) {
                        resultMap.put(brief, item);//更新为更高的score
                    }
                } else {
                    resultMap.put(brief, item);
                }
            }
            List<Map<String, Object>> resultList = new ArrayList<>();
            for (Map.Entry<String, Map<String, Object>> entry : resultMap.entrySet()) {
                // 把每个Entry的value（即内部的Map）提取出来
                resultList.add(entry.getValue());
            }
            for (int i = 0; i < resultList.size() - 1; i++) {
                boolean swapped = false;
                for (int j = 0; j < resultList.size() - 1 - i; j++) {
                    BigDecimal score1 = (BigDecimal) resultList.get(j).get("score");

                    BigDecimal score2 = (BigDecimal) resultList.get(j + 1).get("score");

                    if (score1.compareTo(score2) < 0) {
                        Map<String, Object> temp = resultList.get(j);
                        resultList.set(j, resultList.get(j + 1));
                        resultList.set(j + 1, temp);
                        swapped = true;
                    }
                }
                if (!swapped) break;//没换位提前终止
            }
            resultList = resultList.subList(0, Math.min(limit, resultList.size()));
            return ResultUtil.success(resultList);
        } finally {
            conn.disconnect();
        }
    }
}
